package main

import (
	"container/list"
	"syscall"
)

type Loop struct {
	idleQueue    list.List
	handleQueue  list.List
	watcherQueue list.List

	flags    uint32
	watchers map[int]*io
	epfd     int
}

func (this *Loop) Init() error {
	var err error
	this.watchers = make(map[int]*io)
	this.epfd, err = syscall.EpollCreate(256)
	return err
}

func (this *Loop) NewServer() error {
	return nil
}

func (this *Loop) Start() {
	for {
		this.poll()
	}
}

func (this *Loop) poll() error {
	if len(this.watchers) == 0 {
		return nil
	}

	e := &syscall.EpollEvent{}
	for _, io := range this.watchers {
		e.Events = io.pevents
		e.Fd = int32(io.fd)

		var op int
		if io.cevents == 0 {
			op = syscall.EPOLL_CTL_ADD
		} else {
			op = syscall.EPOLL_CTL_MOD
		}

		if err := syscall.EpollCtl(this.epfd, op, int(e.Fd), e); err != nil {
			panic(err)
		}
		io.cevents = io.pevents
	}

	var events [1024]syscall.EpollEvent
	nfds, err := syscall.EpollWait(this.epfd, events[:], -1)
	if err != nil {
		return err
	}

	for i := 0; i < nfds; i++ {
		e = &events[i]
		if e.Fd == -1 {
			continue
		}

		io := this.watchers[int(e.Fd)]
		if io == nil {
			/* File descriptor that we've stopped watching, disarm it.
			 *
			 * Ignore all errors because we may be racing with another thread
			 * when the file descriptor is closed.
			 */
			syscall.EpollCtl(this.epfd, syscall.EPOLL_CTL_DEL, int(e.Fd), e)
			continue
		}

		/* Give users only events they're interested in. Prevents spurious
		 * callbacks when previous callback invocation in this loop has stopped
		 * the current watcher. Also, filters out events that users has not
		 * requested us to watch.
		 */
		e.Events &= io.pevents
		if e.Events != 0 {
			io.cb(this, e.Events)
		}
	}

	return nil
}
